package com.naiterui.ehp.bs.doctor.service.user.impl;

import static com.naiterui.ehp.bp.domain.Licence.*;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.naiterui.ehp.bp.domain.Doctor;
import com.naiterui.ehp.bp.domain.Licence;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.beans.BeanUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bs.doctor.dao.IDoctorDao;
import com.naiterui.ehp.bs.doctor.dao.user.ILicenceDao;
import com.naiterui.ehp.bs.doctor.exception.ExceptionCodes;
import com.naiterui.ehp.bs.doctor.service.user.ILicenceService;
import com.naiterui.ehp.bs.doctor.utils.AdAttchmentHandle;
import com.naiterui.ehp.bs.doctor.utils.ImageUrlUtil;
import com.naiterui.ehp.bs.doctor.vo.*;
import com.naiterui.ehp.bs.doctor.vo.licence.LicenceVOFactory;

@Service
public class AdLicenceServiceImpl implements ILicenceService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AdLicenceServiceImpl.class);

    public static final String SEAL_PATH_PRE_DR = ConfigUtil.getString("esign.seal.path") + "dr/";
    // 医生图片访问地址前缀
    /** 医生图片类型 - 签章图片 */
    public static final int DOCTOR_FILE_TYPE_SEAL_IMG = 7;
    @Value("${file.base.prefix}")
    private String fileBasePath;
    @Value("${ehp.domain.img}")
    private String imgDomain;

    @Autowired
    private ILicenceDao licenceDao;

    @Autowired
    private IDoctorDao doctorDao;

    /**
     * 处理系统中的文件上传和下载的公共服务类
     */
    @Autowired
    private AdAttchmentHandle adAttchmentHandle;

    /**
     * 根据资质类型获取医生资质信息
     *
     * @param doctorId 医生ID
     * @param types    多个资质类型
     *
     * @return 组装好的资质信息
     */
    @Override
    public Map<Integer, LicenceVO> getLicencesByType(long doctorId, Integer... types) {
        Map<Integer, Licence> licenceMap = licenceDao.getLicenceByDoctorId(doctorId, types);
        Map<Integer, LicenceVO> licenceVOMap = new HashMap<>();
        for (Integer type : types) {
            Licence licence = licenceMap.get(type);
            LicenceVO licenceVO = LicenceVOFactory.createFromLicence(licence);
            licenceVOMap.put(type, licenceVO);
        }
        return licenceVOMap;
    }

    @Override
    public IdCardVO getIdCardByDoctor(long doctorId) {
        Integer type = Licence.DOCTOR_LICENCE_TYPE_IDCARD;
        Map<Integer, LicenceVO> vos = getLicencesByType(doctorId, type);
        IdCardVO idCardVO = null;
        if (vos.get(type) instanceof IdCardVO) {
            idCardVO = (IdCardVO) vos.get(type);
        }
        return idCardVO;
    }

    /**
     * 获取身份证，CA凭证生成专用
     * ！！！该方法返回的身份证图片非可访问地址！！！
     *
     * @param doctorId
     *
     * @return
     *
     * @Author Amber
     * @Date 2017年8月15日
     * @see ILicenceService#getIdCardLicence(long)
     * @since 1.0.0
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public IdCardVO getIdCardLicence(long doctorId) {
        // 写库查询，避免备案通过时由于读写库同步导致读不到数据
        Licence licence = licenceDao.getLicenceByType(doctorId, Licence.DOCTOR_LICENCE_TYPE_IDCARD);
        IdCardVO idCardVO = new IdCardVO();
        if (licence != null) {
            BeanUtil.copyPropertiesIgnoreNull(licence, idCardVO, "urls");
            List<String> urls = Lists.newArrayList();
            String url = licence.getUrl();
            if (StringUtils.isNoneBlank(url)) {
                String[] urlArray = url.split(",");
                for (String u : urlArray) {
                    urls.add(ConfigUtil.getString("adBaseUpload") + u);
                }
            }
            idCardVO.setUrls(urls);
        }
        return idCardVO;
    }


    /**
     * 通过医生ID和类型删除文件，同时返回资质信息
     *
     * @param doctorId 医生ID
     * @param types    资质类型
     *
     * @return 如果没有查询到，那么就返回空，如果查询到，那么删除文件，同时返回
     */
    private Map<Integer, Licence> deleteLicencesByType(long doctorId, Integer... types) {
        Map<Integer, Licence> integerLicenceMap = Maps.newHashMap();

        Map<Integer, Licence> licenceByDoctorId = licenceDao.getLicenceByDoctorId(doctorId, types);

        for (Integer type : types) {
            // 如果不存在KEY，那么就增加KEY
            if (!licenceByDoctorId.containsKey(type)) {
                licenceByDoctorId.put(type, new Licence(doctorId, type));
            }
            Licence licence = licenceByDoctorId.get(type);
            Integer typeState = licence.getType();
            // 图片地址
            String paths = licence.getUrl();
            if (StringUtils.isNotEmpty(paths)) {
                licence.setChangedAt(new Date());
                licence.setChangedBy("system");
            }
            integerLicenceMap.put(typeState, licence);
        }
        return integerLicenceMap;
    }

    /**
     * 通过医生ID和类型上传医生资质
     *
     * @param doctorId      医生ID
     * @param type          资质类型
     * @param multipartFile 资质文件
     * @param compress      是否压缩，默认不压缩
     *
     * @return 保存后的地址
     *
     * @throws BusinessException 文件上传失败
     */
    public String saveOneFile(long doctorId, int type, MultipartFile multipartFile, boolean compress)
        throws BusinessException {
        return adAttchmentHandle.upload(TYPE_TO_ATTCHMENT_TYPE.get(type), multipartFile, compress, doctorId + "");
    }

    /**
     * 更新认证信息
     * LicenceServiceImpl.saveOrUpdate()
     *
     * @param licence
     *
     * @Author YongYang
     * @Date 2018年3月30日
     * @since 1.0.0
     */
    @Override
    public void saveOrUpdate(Licence licence) {
        licenceDao.saveOrUpdate(licence);
    }

    @Override
    public Licence getLicenceByType(Long doctorId, Integer type) {
        return licenceDao.getLicenceByType(doctorId, type);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAuth(Long doctorId, LicenseParam licenseParam) throws BusinessException {
        Map<Integer, Licence> doctorLicences = deleteLicencesByType(doctorId, DOCTOR_LICENCE_TYPE_AVATAR, DOCTOR_LICENCE_TYPE_EMCARD,
                DOCTOR_LICENCE_TYPE_MEDICAL);
        // 保存头像
        MultipartFile avatar = licenseParam.getAvatar();
        if (avatar != null) {
            Licence avatarLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_AVATAR);
            String avatarPath = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_AVATAR, avatar, false);
            avatarLicence.setUrl(avatarPath);
            Doctor doctor = doctorDao.get(doctorId);
            doctor.setHeadUrl(avatarPath);
            doctorDao.update(doctor);
            licenceDao.saveOrUpdate(avatarLicence);
        }

        // 保存工作证
        MultipartFile emCard = licenseParam.getEmCard();
        if (emCard != null) {
            Licence emcardLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_EMCARD);
            String emcardPath = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_EMCARD, emCard, false);
            emcardLicence.setUrl(emcardPath);
            licenceDao.saveOrUpdate(emcardLicence);
        }

        // 医师执业证
        MultipartFile medical = licenseParam.getMedical();
        MultipartFile supplyMedical = licenseParam.getSupplyMedical();
        if (medical != null) {
            Licence medicalLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_MEDICAL);
            String url = "";
            // 执业证图片
            if (medical != null) {
                url = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_MEDICAL, medical, false);
            }

            // 执业证补充图片
            if (supplyMedical != null) {
                String supplyMedicalPath = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_MEDICAL, supplyMedical, false);
                url = StringUtils.isNotBlank(url) ? Joiner.on(",").join(url, supplyMedicalPath) : supplyMedicalPath;
            }

            medicalLicence.setUrl(url);
            licenceDao.saveOrUpdate(medicalLicence);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateRecord(RecordParamVO recordParam) throws BusinessException {
        Long doctorId = recordParam.getDoctorId();

        Map<Integer, Licence> doctorLicences = deleteLicencesByType(doctorId, DOCTOR_LICENCE_TYPE_IDCARD, DOCTOR_LICENCE_TYPE_TITLECERTIFICATE,
                DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE);

        // 身份证信息
        MultipartFile idCardUp = recordParam.getIdCardUp();
        MultipartFile idCardDown = recordParam.getIdCardDown();
        String idNumber = recordParam.getIdNumber();
        if (idCardUp != null || idCardDown != null || StringUtils.isNotBlank(idNumber)) {
            List<Licence> licences = licenceDao.getLicenceByTypeAndNumber(DOCTOR_LICENCE_TYPE_IDCARD, idNumber);
            if (licences.size() > 1) {
                throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
            }
            if (licences.size() == 1) {
                if (!doctorId.equals(licences.get(0).getDoctorId()) && idNumber.equals(licences.get(0).getNumber())) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
                }
            }
            Licence idCardLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_IDCARD);
            String idCardLicenceNumber = idCardLicence.getNumber();
            if (StringUtils.isNotBlank(idCardLicenceNumber)) {
                if (!doctorId.equals(idCardLicence.getDoctorId()) && idNumber.equals(idCardLicenceNumber)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
                }
            }
            // 身份证地址拆分
            String[] path = { "", "" };
            String url = idCardLicence.getUrl();
            if (StringUtils.isNotBlank(url) && url.contains(",")) {
                path = url.split(",");
            }

            // 保存身份证正面
            if (idCardUp != null) {
                path[0] = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_IDCARD, idCardUp, true);
            }

            // 保存身份证反面
            if (idCardDown != null) {
                path[1] = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_IDCARD, idCardDown, true);
            }

            // 身份证号
            if (StringUtils.isNotBlank(idNumber)) {
                idCardLicence.setNumber(idNumber);
            }

            idCardLicence.setUrl(Joiner.on(",").join(path[0], path[1]));
            licenceDao.saveOrUpdate(idCardLicence);
        }

        // 保存职称证书
        MultipartFile titleCertificate = recordParam.getTitleCertificate();
        if (titleCertificate != null) {
            Licence titleCertificateLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_TITLECERTIFICATE);
            titleCertificateLicence.setUrl(saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_TITLECERTIFICATE, titleCertificate, false));
            licenceDao.saveOrUpdate(titleCertificateLicence);
        }

        // 医师资格证
        MultipartFile qualification = recordParam.getQualification();
        MultipartFile supplyQualification = recordParam.getSupplyQualification();
        String quaNumber = recordParam.getQuaNumber();
        if (qualification != null || supplyQualification != null || StringUtils.isNotBlank(quaNumber)) {
            Licence certificate = doctorLicences.get(DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE);
            String url = "";

            // 资格证
            if (qualification != null) {
                url = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE, qualification, false);
            }

            // 资格证补充图片
            if (supplyQualification != null) {
                String supplyPath = saveOneFile(doctorId, DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE, supplyQualification, false);
                url = StringUtils.isNotBlank(url) ? Joiner.on(",").join(url, supplyPath) : supplyPath;
            }

            if (StringUtils.isNotBlank(url)) {
                certificate.setUrl(url);
            }

            if (StringUtils.isNotBlank(quaNumber)) {
                certificate.setNumber(quaNumber);
            }
            licenceDao.saveOrUpdate(certificate);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAuthNew(Long doctorId, LicenseNewParam licenseParam) throws BusinessException {
        Map<Integer, Licence> doctorLicences = deleteLicencesByType(doctorId, DOCTOR_LICENCE_TYPE_AVATAR,
            DOCTOR_LICENCE_TYPE_EMCARD, DOCTOR_LICENCE_TYPE_MEDICAL);

        // 保存头像
        String avatarUrl = licenseParam.getAvatarUrl();
        if (StringUtils.isNotBlank(avatarUrl)) {
            Licence avatarLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_AVATAR);
            String avatarPath = avatarUrl.replaceAll(imgDomain, "");
            avatarLicence.setUrl(avatarPath);
            Doctor doctor = doctorDao.get(doctorId);
            doctor.setHeadUrl(avatarPath);
            doctorDao.update(doctor);
            licenceDao.saveOrUpdate(avatarLicence);
        }

        // 保存工作证
        String emCardUrl = licenseParam.getEmCardUrl();
        if (StringUtils.isNotBlank(emCardUrl)) {
            Licence emcardLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_EMCARD);
            String emcardPath = emCardUrl.replaceAll(imgDomain, "");
            emcardLicence.setUrl(emcardPath);
            licenceDao.saveOrUpdate(emcardLicence);
        }

        // 医师执业证
        String medicalUrl = licenseParam.getMedicalUrl();
        String supplyMedicalUrl = licenseParam.getSupplyMedicalUrl();
        if (StringUtils.isNotBlank(medicalUrl) || StringUtils.isNotBlank(supplyMedicalUrl)) {
            Licence medicalLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_MEDICAL);
            String url = "";
            // 执业证照片
            if (StringUtils.isNotBlank(medicalUrl)) {
                url = medicalUrl.replaceAll(imgDomain, "");
            }
            // 执业证补充图片
            if (StringUtils.isNotBlank(supplyMedicalUrl)) {
                String supplyMedicalPath = supplyMedicalUrl.replaceAll(imgDomain, "");
                url = StringUtils.isNotBlank(url) ? Joiner.on(",").join(url, supplyMedicalPath) : supplyMedicalPath;
            }
            medicalLicence.setUrl(url);
            licenceDao.saveOrUpdate(medicalLicence);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRecordNew(RecordNewParamVO recordParam) throws BusinessException {
        Long doctorId = recordParam.getDoctorId();

        Map<Integer, Licence> doctorLicences = deleteLicencesByType(doctorId, DOCTOR_LICENCE_TYPE_IDCARD,
            DOCTOR_LICENCE_TYPE_TITLECERTIFICATE, DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE);

        // 身份证信息
        String idCardUpUrl = recordParam.getIdCardUpUrl();
        String idCardDownUrl = recordParam.getIdCardDownUrl();
        String idNumber = recordParam.getIdNumber();
        if (StringUtils.isNotBlank(idCardUpUrl) || StringUtils.isNotBlank(idCardDownUrl)
            || StringUtils.isNotBlank(idNumber)) {
            List<Licence> licences = licenceDao.getLicenceByTypeAndNumber(DOCTOR_LICENCE_TYPE_IDCARD, idNumber);
            if (licences.size() > 1) {
                throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
            }
            if (licences.size() == 1) {
                if (!doctorId.equals(licences.get(0).getDoctorId()) && idNumber.equals(licences.get(0).getNumber())) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
                }
            }
            Licence idCardLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_IDCARD);
            String idCardLicenceNumber = idCardLicence.getNumber();
            if (StringUtils.isNotBlank(idCardLicenceNumber)) {
                if (!doctorId.equals(idCardLicence.getDoctorId()) && idNumber.equals(idCardLicenceNumber)) {
                    throw new BusinessException(ExceptionCodes.DOCTOR_RECORD_INFO_ID_NUMBER_IS_EXISTS);
                }
            }
            // 身份证地址拆分
            String[] path = {"", ""};
            String url = idCardLicence.getUrl();
            if (StringUtils.isNotBlank(url) && url.contains(",")) {
                path = url.split(",");
            }

            // 保存身份证正面
            if (StringUtils.isNotBlank(idCardUpUrl)) {
                path[0] = idCardUpUrl.replaceAll(imgDomain, "");
            }

            // 保存身份证反面
            if (StringUtils.isNotBlank(idCardDownUrl)) {
                path[1] = idCardDownUrl.replaceAll(imgDomain, "");
            }

            // 身份证号
            if (StringUtils.isNotBlank(idNumber)) {
                idCardLicence.setNumber(idNumber);
            }

            idCardLicence.setUrl(Joiner.on(",").join(path[0], path[1]));
            licenceDao.saveOrUpdate(idCardLicence);
        }

        // 保存职称证书
        String titleCertificateUrl = recordParam.getTitleCertificateUrl();
        if (StringUtils.isNotBlank(titleCertificateUrl)) {
            Licence titleCertificateLicence = doctorLicences.get(DOCTOR_LICENCE_TYPE_TITLECERTIFICATE);
            titleCertificateLicence.setUrl(titleCertificateUrl.replaceAll(imgDomain, ""));
            licenceDao.saveOrUpdate(titleCertificateLicence);
        }

        // 医师资格证
        String qualificationUrl = recordParam.getQualificationUrl();
        String supplyQualificationUrl = recordParam.getSupplyQualificationUrl();
        String quaNumber = recordParam.getQuaNumber();
        if (StringUtils.isNotBlank(qualificationUrl) || StringUtils.isNotBlank(supplyQualificationUrl)
            || StringUtils.isNotBlank(quaNumber)) {
            Licence certificate = doctorLicences.get(DOCTOR_LICENCE_TYPE_QUALIFICATION_CERTIFICATE);
            String url = "";

            // 资格证
            if (StringUtils.isNotBlank(qualificationUrl)) {
                url = qualificationUrl.replaceAll(imgDomain, "");
            }

            // 资格证补充图片
            if (StringUtils.isNotBlank(supplyQualificationUrl)) {
                String supplyPath = supplyQualificationUrl.replaceAll(imgDomain, "");
                url = StringUtils.isNotBlank(url) ? Joiner.on(",").join(url, supplyPath) : supplyPath;
            }

            if (StringUtils.isNotBlank(url)) {
                certificate.setUrl(url);
            }

            if (StringUtils.isNotBlank(quaNumber)) {
                certificate.setNumber(quaNumber);
            }
            licenceDao.saveOrUpdate(certificate);
        }
    }

    @Override
    public String upload(Long doctorId, MultipartFile file, int type) throws BusinessException {
        // 医生签名图片另外处理
        if (type == DOCTOR_FILE_TYPE_SEAL_IMG) {
            LOGGER.info("上传医生签名图片 doctorId:{}, fileName:{}", doctorId, file.getName());
            // 生成签名印章
            String filepath = SEAL_PATH_PRE_DR + doctorId + "_" + System.currentTimeMillis() + "_o.jpg";
            LOGGER.info("上传医生签名图片地址 {}", filepath);
            File signImgFile = new File(filepath);
            try {
                FileUtils.forceMkdirParent(signImgFile);
                FileUtils.copyInputStreamToFile(file.getInputStream(), signImgFile);
            } catch (IOException e) {
                throw new BusinessException(ExceptionCodes.DOCTOR_SEAL_IMG_FAIL);
            }
            String path = filepath.replaceAll(fileBasePath, "");
            return imgDomain + path;
        }
        // 上传医生资质文件
        String url = saveOneFile(doctorId, type, file, false);
        return ImageUrlUtil.getImagePath(url);
    }
}
